﻿#include "InstrumentData.h"
#include <string.h>
#include "Container.h"
#include "../DataStoreLib/IDataStore.h"
//#include "DateTime.h"
#include <cassert>
#include <boost/make_shared.hpp>

//////////////////////////////////////////////////////////////////////
//	class	CInstrument


InstrumentData::InstrumentData()
{
	m_pInstrumentInfo = boost::make_shared<InstrumentInfo>();
	//m_pDataStoreOperator	=	pOpoerator;
	//DateTime cur_day = DateTime::current_time();
	//m_rptTimeBegin = DateTime(cur_day.GetYear(), cur_day.GetMonth(), cur_day.GetDay(), 9, 0, 0);
	//m_rptTimeEnd = DateTime(cur_day.GetYear(), cur_day.GetMonth(), cur_day.GetDay(), 15, 15, 0);
	m_ptBegin = boost::posix_time::ptime(boost::posix_time::min_date_time);
}



InstrumentData::InstrumentData(const char * insID, const char* exID)
{
	m_pInstrumentInfo = boost::make_shared<InstrumentInfo>();
	m_pInstrumentInfo->set_id(exID, insID);
	//DateTime cur_day = DateTime::current_time();
	//m_rptTimeBegin = DateTime(cur_day.GetYear(), cur_day.GetMonth(), cur_day.GetDay(), 9, 0, 0);
	//m_rptTimeEnd = DateTime(cur_day.GetYear(), cur_day.GetMonth(), cur_day.GetDay(), 15, 15, 0);
	m_ptBegin = boost::posix_time::ptime(boost::posix_time::min_date_time);
}

InstrumentData::~InstrumentData()
{
	Clear();
}


        

double InstrumentData::GetReportFactor( int nReportType )
{
	double	factor	=	1;
	if( InstrumentData::reportQuarter == nReportType )
		factor	=	4;
	else if( InstrumentData::reportMid == nReportType )
		factor	=	2;
	else if( InstrumentData::reportQuarter3 == nReportType )
		factor	=	1.333333;
	return factor;
}
void InstrumentData::SetInstrumentID( const char* szExID,const char* szID )
{
	if (m_pInstrumentInfo->is_equal(szExID, szID))
	{
		return ;
	}
	Clear();
	m_pInstrumentInfo->set_id(szExID, szID);
}

const char * InstrumentData::GetInstrumentID()
{
	return m_pInstrumentInfo->get_id();
}

bool InstrumentData::SetInstrumentInfo( InstrumentInfo * pInfo )
{
	if( NULL == pInfo )
	{
		Clear();
		return false;
	}
	if( m_pInstrumentInfo->is_equal( pInfo->GetExchangeID(), pInfo->get_id()) )
	{
		*m_pInstrumentInfo = *pInfo;
		return m_pInstrumentInfo->is_valid();
	}
	Clear();
	*m_pInstrumentInfo = *pInfo;
	return m_pInstrumentInfo->is_valid();
}

InstrumentInfo & InstrumentData::GetInstrumentInfo()	
{
	return *m_pInstrumentInfo;
}
KdataContainer	& InstrumentData::GetKData( int ktype )
{
	auto pKDataIter =
		ktyped_data_containers.find(ktype);
	if (pKDataIter == ktyped_data_containers.end())
	{
		boost::shared_ptr<KdataContainer> pKData =
			boost::make_shared<KdataContainer>();
		pKData->SetKType(ktype);

		ktyped_data_containers.insert(std::make_pair(ktype, pKData));
		return *pKData;
	}
	else
	{
		return *pKDataIter->second;
	}

}
KdataContainer	& InstrumentData::GetKDataMonth( )		
{	
	return GetKData(ktypeMonth);
}
KdataContainer	& InstrumentData::GetKDataWeek( )		
{	
	return GetKData(ktypeWeek);
}
KdataContainer	& InstrumentData::GetKDataDay( )		
{	
	return GetKData(ktypeDay);
}
KdataContainer	& InstrumentData::GetKDataMin60( )		
{	
	return GetKData(ktypeMin60);
}
KdataContainer	& InstrumentData::GetKDataMin30( )		
{	
	return GetKData(ktypeMin30);
}
KdataContainer	& InstrumentData::GetKDataMin15( )		
{	
	return GetKData(ktypeMin15);
}
KdataContainer	& InstrumentData::GetKDataMin5( )		
{	
	return GetKData(ktypeMin5);
}
KdataContainer& InstrumentData::GetKDataMin1()
{
	return GetKData(ktypeMin);
}
ReportContainer & InstrumentData::GetReport( )			
{	if (!m_report)
	{
		m_report = boost::make_shared<ReportContainer>();
	}
	return *m_report;	
}

MinuteContainer & InstrumentData::GetMinute( )			
{	
	if (!m_minute)
	{
		m_minute = boost::make_shared<MinuteContainer>();
	}
	return *m_minute;	
}       
char	* InstrumentData::GetBaseTextPtr( )	
{	
	return (char*)m_pBaseText.c_str();	
}
int	InstrumentData::GetBaseTextLength( )	    
{ 
	return m_pBaseText.length();
}


int InstrumentData::ExtractKData( int period, bool bForced )
{
	switch( period )
	{
	case ktypeMonth:
		{
			if( bForced )
				return KdataContainer::DayToMonth( GetKDataDay(), GetKDataMonth() );
			int compare = GetKDataMonth().CompareLatestDate( GetKDataDay() );
			if( -1 == compare )
				return KdataContainer::DayToMonth( GetKDataDay(), GetKDataMonth() );
			else if( 1 == compare )
				return GetKDataMonth().size();
			else if( GetKDataMonth().size() * 18 < GetKDataDay().size() )
				return KdataContainer::DayToMonth( GetKDataDay(), GetKDataMonth() );
			else
				return GetKDataMonth().size();
		}
		break;
	case ktypeWeek:
		{
			if( bForced )
				return KdataContainer::DayToWeek( GetKDataDay(), GetKDataWeek() );
			int compare = GetKDataWeek().CompareLatestDate( GetKDataDay() );
			if( -1 == compare )
				return KdataContainer::DayToWeek( GetKDataDay(), GetKDataWeek() );
			else if( 1 == compare )
				return GetKDataWeek().size();
			else if( GetKDataWeek().size() * 5 < GetKDataDay().size() )
				return KdataContainer::DayToWeek( GetKDataDay(), GetKDataWeek() );
			else
				return GetKDataWeek().size();
		}
		break;
	case ktypeDay:
		return GetKDataDay().size();
	case ktypeMin60:
		{
			if( bForced )
				return KdataContainer::Min5ToMin60( GetKDataMin5(), GetKDataMin60() );
			int compare = GetKDataMin60().CompareLatestDate( GetKDataMin5() );
			if( -1 == compare )
				return KdataContainer::Min5ToMin60( GetKDataMin5(), GetKDataMin60() );
			else if( 1 == compare )
				return GetKDataMin60().size();
			else if( GetKDataMin60().size() * 12 < GetKDataMin5().size() )
				return KdataContainer::Min5ToMin60( GetKDataMin5(), GetKDataMin60() );
			else
				return GetKDataMin60().size();
		}
		break;
	case ktypeMin30:
		{
			if( bForced )
				return KdataContainer::Min5ToMin30( GetKDataMin5(), GetKDataMin30() );
			int compare = GetKDataMin30().CompareLatestDate( GetKDataMin5() );
			if( -1 == compare )
				return KdataContainer::Min5ToMin30( GetKDataMin5(), GetKDataMin30() );
			else if( 1 == compare )
				return GetKDataMin30().size();
			else if( GetKDataMin30().size() * 6 < GetKDataMin5().size() )
				return KdataContainer::Min5ToMin30( GetKDataMin5(), GetKDataMin30() );
			else
				return GetKDataMin30().size();
		}
		break;
	case ktypeMin15:
		{
			if( bForced )
				return KdataContainer::Min5ToMin15( GetKDataMin5(), GetKDataMin15() );
			int compare = GetKDataMin15().CompareLatestDate( GetKDataMin5() );
			if( -1 == compare )
				return KdataContainer::Min5ToMin15( GetKDataMin5(), GetKDataMin15() );
			else if( 1 == compare )
				return GetKDataMin15().size();
			else if( GetKDataMin15().size() * 3 < GetKDataMin5().size() )
				return KdataContainer::Min5ToMin15( GetKDataMin5(), GetKDataMin15() );
			else
				return GetKDataMin15().size();
		}
		break;
	case ktypeMin5:
		return GetKDataMin5().size();
	default:
		return 0;
	}
}

int InstrumentData::MergeBaseText( InstrumentData &stock )
{
	if( GetBaseTextLength() > 0 )
		return GetBaseTextLength();
	if( stock.GetBaseTextLength() > 0 )
	{
		//if( AllocBaseTextMem( stock.GetBaseTextLength() ) )
		strncpy( GetBaseTextPtr(), stock.GetBaseTextPtr(), stock.GetBaseTextLength() );
		return stock.GetBaseTextLength();
	}
	return 0;
}

int InstrumentData::MergeKData( InstrumentData &stock, int period )
{
	KdataContainer	* pkdata	=	NULL;
	KdataContainer	* pkdata2	=	NULL;
	switch( period )
	{
	case ktypeMonth:
		pkdata	=	&(GetKDataMonth());
		pkdata2	=	&(stock.GetKDataMonth());
		break;
	case ktypeWeek:
		pkdata	=	&(GetKDataWeek());
		pkdata2	=	&(stock.GetKDataWeek());
		break;
	case ktypeDay:
		pkdata	=	&(GetKDataDay());
		pkdata2	=	&(stock.GetKDataDay());
		break;
	case ktypeMin60:
		pkdata	=	&(GetKDataMin60());
		pkdata2	=	&(stock.GetKDataMin60());
		break;
	case ktypeMin30:
		pkdata	=	&(GetKDataMin30());
		pkdata2	=	&(stock.GetKDataMin30());
		break;
	case ktypeMin15:
		pkdata	=	&(GetKDataMin15());
		pkdata2	=	&(stock.GetKDataMin15());
		break;
	case ktypeMin5:
		pkdata	=	&(GetKDataMin5());
		pkdata2	=	&(stock.GetKDataMin5());
		break;
	default:
//		assert( FALSE );
		return 0;
	}

	return pkdata->MergeKData( pkdata2 );
}

// int CInstrument::MergeDRData( CInstrument &stock )
// {
// 	if( GetDRData().GetSize() < stock.GetDRData().GetSize() )
// 		GetDRData().Copy( stock.GetDRData() );
// 	return GetDRData().GetSize();
// }
// 
// int CInstrument::StoreDRData( )
// {
// 	if( m_pDatabase )
// 		return m_pDatabase->StoreDRData( this );
// 	return 0;
// }

void InstrumentData::Clear( )
{
	if (m_pInstrumentInfo)
	{
		m_pInstrumentInfo->clear();
	}
	
	m_pBaseText.clear();


	for (auto kIter = ktyped_data_containers.begin(); kIter != ktyped_data_containers.end();++kIter)
	{
		if (kIter->second)
		{
			kIter->second->Clear();
		}
	}
	if (m_report)
	{
		m_report->resize(0);
	}
	
	if (m_minute)
	{
		m_minute->resize(0);
	}
}


DWORD InstrumentData::GetLatestDate()
{
	return GetKDataDay().GetDate(0);
}



std::string InstrumentData::GetMainCode()
{
	if (std::string(m_pInstrumentInfo->ProductID).empty() || std::string(m_pInstrumentInfo->ExpireDate).empty())
	{
		//获取当前年月;
		return GetCurMonthCode();
	}
	else
	{
// 		DWORD dwExpireDate=atoi(m_pInstrumentInfo->ExpireDate);
// 		DateTime tday=DateTime::GetTradingDay();
// 		if (dwExpireDate<tday.ToInstrumentTimeDay())
// 		{
// 			//合约已过期;
// 			char main_code[31]={0};
// 			DWORD dwYear=tday.GetYear();
// 			for (int i=1;i<12;i++)
// 			{
// 				int month=tday.GetMonth()+i;
// 				if (month>12)
// 				{
// 					month=month-12;
// 					dwYear+=1;
// 				}
// 				sprintf(main_code,"%s%02d%02d",m_pInstrumentInfo->ProductID,dwYear%100,month);
// 				instrument_info info;
// 				if (instrument_container::get_instance().GetInstrumentInfo(main_code,&info))
// 				{
// 					break;
// 				}
// 			}
// 			return main_code;
// 		}
// 		else
// 		{
// 			return GetCurMonthCode();
// 		}
	}
	return m_pInstrumentInfo->szCode;
}

std::string InstrumentData::GetCurMonthCode()
{
// 	DateTime cur_ym=DateTime::current_time();
// 	char ym[4]={0};
// 	sprintf(ym,"%02d%02d",cur_ym.GetYear()%100,cur_ym.GetMonth());

	std::string InstId(m_pInstrumentInfo->szCode);
	//InstId.replace(InstId.end()-4,InstId.end(),ym);
	return InstId;
}

// void InstrumentData::SetDataStore(boost::shared_ptr<IDataStore> pDataStore)
// {
// 	m_pDataStoreOperator = pDataStore;
// }

bool InstrumentData::update(const Tick* pTick)
{
	//更新数据;
	if (!pTick)
	{
		return false;
	}
	if (m_report)
	{
		m_report->push_back(*pTick);
	}

	if (m_minute)
	{
		m_minute->update(pTick);
	}
	if (m_pInstrumentInfo)
	{
		InstrumentInfo::update(*m_pInstrumentInfo, pTick);
	}
	//更新K线数据;
	for (auto kIter = ktyped_data_containers.begin(); kIter != ktyped_data_containers.end();++kIter)
	{
		if (kIter->second)
		{
			kIter->second->update(pTick);
		}
	}

	return true;
}

boost::shared_ptr<Tick> InstrumentData::GetLastTick()
{
	return boost::make_shared<Tick>(m_pInstrumentInfo->m_reportLatest);

}

std::vector<int> InstrumentData::GetKTypes()
{
	std::vector<int> ktypes;
	for (auto kIter = ktyped_data_containers.begin();kIter!=ktyped_data_containers.end();++kIter)
	{
		ktypes.push_back(kIter->first);
	}
	return ktypes;
}
